package ita.class1.group2.supermarket.common.captain;

import ita.class1.group2.supermarket.common.captain.handler.RequestHandler;
import ita.class1.group2.supermarket.common.captain.handler.ResponseHandler;
import ita.class1.group2.supermarket.common.captain.manager.ComponentManager;
import ita.class1.group2.supermarket.common.captain.manager.ControllerManager;
import ita.class1.group2.supermarket.common.captain.model.Path;
import org.apache.log4j.Logger;
import org.omg.PortableInterceptor.LOCATION_FORWARD;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

public class CaptainRouter {

    private static final Logger LOGGER = Logger.getLogger(CaptainRouter.class);

    private static List<String> ACCEPT_METHODS;

    static {
        ACCEPT_METHODS = new ArrayList<String>();
        ACCEPT_METHODS.add("GET");
        ACCEPT_METHODS.add("POST");
        ACCEPT_METHODS.add("PUT");
        ACCEPT_METHODS.add("DELETE");
    }

    private ControllerManager controllerManager;
    private ComponentManager componentManager;
    private RequestHandler requestHandler;
    private ResponseHandler responseHandler;

    public CaptainRouter(ControllerManager controllerManager, ComponentManager componentManager) {
        this.controllerManager = controllerManager;
        this.componentManager = componentManager;
        this.requestHandler = new RequestHandler();
        this.responseHandler = new ResponseHandler();
    }

    public Object route(HttpServletRequest httpServletRequest) throws Exception {

        if (ACCEPT_METHODS.contains(httpServletRequest.getMethod())) {

            String contextPath = httpServletRequest.getContextPath();
            String requestURI = httpServletRequest.getRequestURI();

            for (Path path: this.controllerManager.getControllers().keySet()) {
                if (path.checkURI(requestURI, contextPath)) {
                    List<Object> invokeParams = requestHandler.handle(path, httpServletRequest);
                    Method method = this.controllerManager.getControllers().get(path);
                    List<Object> args = new ArrayList<Object>();
                    for(Class cls: method.getParameterTypes()) {
                        for (Object param: invokeParams) {
                            if (cls.isAssignableFrom(param.getClass())) {
                                args.add(param);
                            }
                        }
                    }
                    return method.invoke(componentManager.getComponentsMap().get(method.getDeclaringClass()), args.toArray());
                }
            }

        } else {
            LOGGER.warn("Request method not support: " + httpServletRequest.getMethod());
        }

        return null;
    }

    public void to(HttpServletResponse response, Object object) throws Exception {
        this.responseHandler.handle(response, object);
    }

}
